#ifndef _SOCKETACCEPTOR_HPP_
#define _SOCKETACCEPTOR_HPP_

#include "jhdefs.hpp"
#include "net/Socket.hpp"
#include "net/StreamSocket.hpp"
#include "net/ServerSocket.hpp"
#include "net/SocketReactor.hpp"
#include "net/SocketNotification.hpp"
#include "msg/abstractobserver.hpp"
using JHCPP::msg::TObserver;

NET_NAMESPACE_BEGIN

template <class T>
class TSocketAcceptor
{
public:
	explicit TSocketAcceptor(CServerSocket& socket) : m_socket(socket), m_pReactor(0)
	{
	}

	TSocketAcceptor(CServerSocket& socket, CSocketReactor& reactor) : m_socket(socket), m_pReactor(&reactor)
	{
		m_pReactor->addEventHandler(m_socket, TObserver<TSocketAcceptor, 
			CReadableNotification>(*this, &TSocketAcceptor::onAccept));
	}

	virtual ~TSocketAcceptor()
	{
		try
		{
			if (m_pReactor)
			{
				m_pReactor->removeEventHandler(m_socket, TObserver<TSocketAcceptor,
					CReadableNotification>(*this, &TSocketAcceptor::onAccept));
			}
		}
		catch (...)
		{
			jh_unexpected();
		}
	}

	void setReactor(CSocketReactor& reactor)
	{
		m_pReactor = &reactor;
		if (!m_pReactor->hasEventHandler(m_socket, TObserver<TSocketAcceptor,
			CReadableNotification>(*this, &TSocketAcceptor::onAccept)))
		{
			registerAcceptor(reactor);
		}
	}

	virtual void registerAcceptor(CSocketReactor& reactor)
	{
		if (m_pReactor)
			InvalidAccessException("Acceptor already registered.");

		m_pReactor = &reactor;
		m_pReactor->addEventHandler(m_socket, TObserver<TSocketAcceptor, CReadableNotification>(*this, &TSocketAcceptor::onAccept));
	}

	virtual void unregisterAcceptor()
	{
		if (m_pReactor)
		{
			m_pReactor->removeEventHandler(m_socket, TObserver<TSocketAcceptor, CReadableNotification>(*this, &TSocketAcceptor::onAccept));
		}
	}

	void onAccept(CReadableNotification* pNotification)
	{
		pNotification->release();
		CStreamSocket sock = m_socket.acceptConnection();
		m_pReactor->wakeUp();
		createServiceHandler(sock);
	}

protected:
	virtual T* createServiceHandler(CStreamSocket& socket)
	{
		return new T(socket, *m_pReactor);
	}

	CSocketReactor* reactor()
	{
		return m_pReactor;
	}

	CSocket& socket()
	{
		return m_socket;
	}

private:
	TSocketAcceptor();
	TSocketAcceptor(const TSocketAcceptor&);
	TSocketAcceptor& operator = (const TSocketAcceptor&);

	CServerSocket   m_socket;
	CSocketReactor* m_pReactor;
};

NET_NAMESPACE_END

#endif
